#include "device_type.h"
#ifdef SM_SMART_PLUG
#include "stddef.h"
#include "app_api.h"
#include "app_log.h"
#include "app_cli_cmd.h"
#include "bsp_gpio.h"
#include "app_button.h"
#include "app_led.h"
#include "bsp_iadc.h"
#include "em_emu.h"
#include "softwareMultiTimer.h"
#include "device.h"
#include "bsp_system.h"
#include "net_protocol.h"
#include "app_key_value.h"
#include "bsp_rmu.h"
#include "bsp_wdog.h"
#include "RBFVersion.h"
#include "git_version.h"
#include "net_aseq.h"
#include "net_packet.h"
#include "app_bl0937.h"
#include "em_rmu.h"

#define DEVICE_TX_POWER_DEFAULT  (200)
#define DEVICE_CTUNE_DEFAULT     (125)
#define DEVICE_LFXO_CTUNE_DEFAULT (40)
#define IADC_TIMER_INTERVAL      (240)
#define APP_MAJOR_VERSION        (1)
#define APP_MINOR_VERSION        (1)
#define APP_STAGE_VERSION        (2) //max 255
#define SENSOR_VERSION           ((APP_MAJOR_VERSION << 16)|(APP_MINOR_VERSION<<8)|(APP_STAGE_VERSION))

#ifdef SM_SMART_PLUG_ITA
#define PLUG_RELAY_PORT     (gpioPortC)
#define PLUG_RELAY_PIN      (0U)

#define PLUG_LED_PORT       (gpioPortD)
#define PLUG_LED_PIN        (3U)
#define PLUG_LED_INIT       (1)
#define PLUG_LED_VALID      (0)

#define PLUG_KEY_PORT       (gpioPortC)
#define PLUG_KEY_PIN        (1U)
#else
#define PLUG_RELAY_PORT     (gpioPortA)
#define PLUG_RELAY_PIN      (6U)

#define PLUG_LED_PORT       (gpioPortC)
#define PLUG_LED_PIN        (2U)
#define PLUG_LED_INIT       (0)
#define PLUG_LED_VALID      (1)

#define PLUG_KEY_PORT       (gpioPortA)
#define PLUG_KEY_PIN        (5U)
#endif

static void setTxpowerDefaule(void);
static void setCtuneDefaule(void);
static void setLfxoCtuneDefaule(void);
static void set_led_state(void);
static void SM_button_init(void);
static void energyStateCallbackInit(void);
static void SM_relay_gpio_init(void);
static void SM_relay_gpio_state_set(uint8_t state);
static uint32_t SM_relay_state_get(void);
static void power_on_led_start(void);
static void SM_iadc_init(void);
static void printSoftWareInformation(void);

static uint8_t s_option[3] = {0x00};
static uint8_t childLockState = 0;

/**
 * @brief: 弱点继电器项目相关外设初始化
 * */
void SM_main(void)
{
  setTxpowerDefaule();
  setCtuneDefaule();
  setLfxoCtuneDefaule();
  SM_button_init();
  energyStateCallbackInit();
  bl0937_init();
  SM_relay_gpio_init();
  power_on_led_start();
  SM_iadc_init();
  startWatchDogTimer();
  printSoftWareInformation();
}

/**
 * @brief: 遥控器项目while函数相关处理
 * */
void SM_process(void)
{
  feedWatchDogHandler();
  SM_key_value_handler();
  if(getReadEnergyState()) {
      readEnergyHandler();
  }
}

/******************get device sleep state***************************/

bool device_sleep_state_get(void)
{
  return true;
}

/**************** set tx power/ctune defaule***********************/
static void setTxpowerDefaule(void)
{
  int16_t txPowerDeciDbm = 0;
  int ret = getThisParam(RfTxPower, &txPowerDeciDbm);
  if(ret != 0) {
      txPowerDeciDbm = DEVICE_TX_POWER_DEFAULT;
      setThisParam(RfTxPower, &txPowerDeciDbm);
  }
  RAIL_Status_t status = bsp_rf_set_tx_power_bdm(txPowerDeciDbm);
  if (status != RAIL_STATUS_NO_ERROR) {
      DS_app_log_error("set tx power error, status = 0x%x\r\n", status);
  }
}

static void setCtuneDefaule(void)
{
  uint32_t ctune = 0;
  int ret = getThisParam(RfCtune, &ctune);
  if(ret != 0) {
      ctune = DEVICE_CTUNE_DEFAULT;
      setThisParam(RfCtune, &ctune);
  }
  RAIL_Status_t status = bsp_rf_set_ctune(ctune);
  if (status != RAIL_STATUS_NO_ERROR) {
      DS_app_log_error("set ctune error, status = 0x%x\r\n", status);
  }
}

static void setLfxoCtuneDefaule(void)
{
  uint8_t ctune = 0;
  int ret = getThisParam(lfxoCtune, &ctune);
  if(ret != 0) {
      ctune = DEVICE_LFXO_CTUNE_DEFAULT;
      setThisParam(lfxoCtune, &ctune);
  }
  CMU_OscillatorTuningSet(cmuOsc_LFXO,ctune);
}

/************************button handler****************************/

static struct Button btn = {0};
static MultiTimer buttonTimer[2] = {
    {.Handle = 0},
    {.Handle = 1},
};

keyValue_t outputKeyValue = {0};
static uint8_t clickRepeat = 0;
/**
 * @brief: button timer callback,每10ms轮询一次button状态
 * */
static void buttonTimerCallback(MultiTimer* timer, void *userData)
{
  (void)userData;
  if(timer->Handle == 0) {
      button_handler(&btn);
  }
  else if(timer->Handle == 1) {
      DS_app_log_error("button repeat = %d \r\n", clickRepeat);
      if(clickRepeat == 4) {
          outputKeyValue.value[0] &= ~(0x01<<7);
          set_key_value(&outputKeyValue);
          childLockState = 0;
          setThisParam(childLock, &childLockState);
      }
      clickRepeat = 0;
  }
}

/**
 * @brief:button 1 引脚状态改变时启动button timer
 * */
static void ds_btn_state_change_callback(uint8_t intNo, void *ctx)
{
  (void)intNo;
  (void)ctx;

  if(buttonTimer[0].status == EN_MULTITIMER_STATUS_IDLE) {
      button_handler(&btn);
  }
}

static ds_button_t button = {
    .port = PLUG_KEY_PORT,
    .pin = PLUG_KEY_PIN,
    .mode = gpioModeInputPull,
    .initial = 1,
    .valid = 0,
    .ds_button_state_change = ds_btn_state_change_callback,
};

/**
 * @brief: 读取button引脚状态
 * @param： button id
 * @return： gpio 状态
 * */
static uint8_t read_button_GPIO(uint8_t button_id)
{
  // you can share the GPIO read function with multiple Buttons
  switch(button_id)
  {
    case 0:
      return read_button_level(&button);
      break;
    default:
      return 0;
      break;
  }
}

static MultiTimer commissionTimer = {.Handle = 0};
static void commissionCallback(MultiTimer* timer, void *userData)
{
  static uint8_t count = 0;
  (void)userData;

  count ++;
  if(EN_MSG_STATUS_JOIN_CONFIRM_SUCCESS == get_register_status()) {
      clear_register_status();
      count = 0;
      uint8_t data[5] = {0x00};
      SM_led_start(data, NONE_BLINK);
  }
  else {
      if(count < 60)
        softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, timer, 32768, commissionCallback,NULL,0);
      else
        count = 0;
  }
}

bool isBattVoltageHigh(void)
{
  return true;
}

void startCommissiongJoin(commissionType_t type, deviceType_t device)
{
  (void)type;
  (void)device;
  if(measure_state_get() != MEASURE_NORMAL)
    return ;

  softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &commissionTimer, 32768, commissionCallback,NULL,0);
  Commissiong_join_node_paging_packet(30);
  uint8_t data[5] = {0,0,3,0,60};
  SM_led_start(data, REGIEST_BLINK);
}

static void btn_press_handler(void* butt)
{
  Button *btn = (Button *)butt;
  uint8_t onoff = 0;

  if(measure_state_get() != MEASURE_NORMAL)
    return ;

  DS_app_log_error("btn id = %d event = %d \r\n", btn->button_id, btn->event);
  if(btn->button_id == 0) {
      if(btn->event == LONG_PRESS_START) {
          if(commissionTimer.status == EN_MULTITIMER_STATUS_IDLE && childLockState == 0) {
          startCommissiongJoin(buttonTrigger, other_device);
          }
      }
      else if(btn->event == SINGLE_CLICK) {
          if((s_option[1] & 0x03) == 0 && childLockState == 0) {
              onoff = (uint8_t)SM_relay_state_get();
              SM_relay_gpio_state_set(!onoff);
              set_key_value(&outputKeyValue);
          }
          else if(childLockState) {
              clickRepeat++;
              softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &buttonTimer[1], 0);
              softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &buttonTimer[1], 32768, buttonTimerCallback,NULL,0);
          }
      }
  }
}

/**
 * @brief: button reed初始化；注册不同状态相关回调函数
 * */
static void SM_button_init(void)
{
  ds_button_init(&button);

  button_init(&btn, &buttonTimer[0], buttonTimerCallback, read_button_GPIO, button.valid, 0);
  button_attach(&btn, LONG_PRESS_START,       btn_press_handler);
  button_attach(&btn, SINGLE_CLICK,           btn_press_handler);
}

/************************led init***************************************/
static MultiTimer ledTimer;
static led_ins_t ledDriver;

static ds_gpio_t Led = {
    .port = PLUG_LED_PORT,
    .pin = PLUG_LED_PIN,
    .mode = gpioModePushPull,
    .initial = PLUG_LED_INIT,
    .valid = PLUG_LED_VALID,
};

static void set_led_state(void)
{
  uint8_t onoff = (uint8_t)SM_relay_state_get();

  if(onoff){
      ds_gpio_on(&Led);
  }
  else {
      ds_gpio_off(&Led);
  }
}

/**
 * @brief: led闪烁开始
 * @param： led物模型指针；5Bytes：R G Bbitmask bitTime cycleTimes
 * */
void SM_led_start(uint8_t *data, blinkType_t type)
{
  if(type == LED_MODEL_BLINK || type == ALARM_BLINK)
    return;

  led_driver_init(&ledDriver, &ledTimer, Led, Led, Led, data, type);
  if(type == NONE_BLINK) {
      set_led_state();
  }
}

/***********************relay and led init**********************/

static MultiTimer relayTimer = {.Handle = 0};
static uint32_t relayTimes = 0;
static uint32_t relayticks = 0;
static ds_gpio_t relay = {
    .port = PLUG_RELAY_PORT,
    .pin = PLUG_RELAY_PIN,
    .mode = gpioModePushPull,
    .initial = 0,
    .valid = 1,
};

static void SM_relay_gpio_init(void)
{
  ds_gpio_init(&relay);
  ds_gpio_init(&Led);

  uint8_t onoff = 0x00;
  if(getThisParam(onoffState, &onoff) != 0) {
      onoff = 0x01;
      setThisParam(onoffState, &onoff);
  }
  if(getThisParam(ENpbyOption, s_option) != 0) {
      setThisParam(ENpbyOption, s_option);
  }
  if(getThisParam(childLock, &childLockState) != 0) {
      childLockState = 0;
      setThisParam(childLock, &childLockState);
  }
  if(getThisParam(smartPlugTimes, &relayTimes) != 0) {
      relayticks = 0;
  }

  outputKeyValue.id = 0x010;
  outputKeyValue.valueSize = 2;
  outputKeyValue.value[1] = 0;
  if(childLockState) {
      outputKeyValue.value[0] |= (0x01<<7);
  }
  else {
      outputKeyValue.value[0] &= ~(0x01<<7);
  }
  relayticks = relayTimes;

  DS_app_log_info("option[0] = 0x%02x [1] = 0x%02x \r\n", s_option[0], s_option[1]);
  DS_app_log_info("onoff = 0x%02x \r\n", onoff);

  if((RMU_ResetCauseGet() & EMU_RSTCAUSE_POR) == 0) {
      if(onoff == 0) {
          SM_relay_gpio_state_set(0);
      } else {
          SM_relay_gpio_state_set(1);
      }
  }
  else {
      if((s_option[1] & 0x03) == 1 ||
         ((s_option[1] & 0x03) == 0 && ((s_option[0]>>2)&0x03) == 1) ||
         ((s_option[1] & 0x03) == 0 && ((s_option[0]>>2)&0x03) == 2 && onoff == 0)) {
          SM_relay_gpio_state_set(0);
      }
      else if((s_option[1] & 0x03) == 2 ||
          ((s_option[1] & 0x03) == 0 && ((s_option[0]>>2)&0x03) == 0) ||
          ((s_option[1] & 0x03) == 0 && ((s_option[0]>>2)&0x03) == 2 && onoff == 1)) {
          SM_relay_gpio_state_set(1);
      }
  }
}

static void relayTimerCallback(MultiTimer* timer, void *userData)
{
  (void)userData;
  relayticks++;

  if(relayticks >= relayTimes + 300) {
      relayTimes = relayticks;
      setThisParam(smartPlugTimes, &relayTimes);
      DS_app_log_error("relay on times = %ld \r\n", relayticks);
  }

  softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, timer, 32768, relayTimerCallback,NULL,0);
}

static void SM_relay_gpio_state_set(uint8_t state)
{
  DS_app_log_info("onoff = %d \r\n", state);
  if(state) {
      ds_gpio_on(&relay);
      outputKeyValue.value[0] |= 0x01;
      if(relayTimer.status == EN_MULTITIMER_STATUS_IDLE && measure_state_get() == MEASURE_NORMAL)
        softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &relayTimer, 32768, relayTimerCallback,NULL,0);
  }
  else {
      ds_gpio_off(&relay);
      outputKeyValue.value[0] &= ~0x01;
      softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &relayTimer, 0);
  }
  set_led_state();
  setThisParam(onoffState, &state);
}

static uint32_t SM_relay_state_get(void)
{
  return GPIO_PinOutGet(relay.port ,relay.pin);
}

/*****************key value handler*************************/

static MultiTimer optionTimer = {.Handle = 0};
static uint8_t s_state = 0;

static void optionTimeroutHandlerCallback(MultiTimer* timer, void *userData)
{
  (void)userData;
  (void)timer;

  if(s_state) {
      SM_relay_gpio_state_set(1);
  }
  else {
      SM_relay_gpio_state_set(0);
  }
  set_key_value(&outputKeyValue);
}

void recv_option_key_value_handler(uint8_t *option)
{
  if(option[0] != s_option[0] || option[1] != s_option[1] || option[2] != s_option[2]) {
      setThisParam(ENpbyOption, option);
      memcpy(s_option, option, 3);
  }

  if((option[1] & 0x03) == 0) {

  } else if((option[1] & 0x03) == 1) {
      SM_relay_gpio_state_set(0);
  } else if((option[1] & 0x03) == 2) {
      SM_relay_gpio_state_set(1);
  }
}

/************************operation key value handler*************************************/

void recv_operation_key_value_handler(uint8_t *operation)
{
  uint8_t timeout = operation[1];
  uint8_t onoff = 0;

  if((operation[0] & 0x0f) == 0) {

  } else if((operation[0] & 0x0f) == 1) {
      SM_relay_gpio_state_set(1);
  } else if((operation[0] & 0x0f) == 2) {
      SM_relay_gpio_state_set(0);
  } else if((operation[0] & 0x0f) == 3) {
      onoff = (uint8_t)SM_relay_state_get();
      SM_relay_gpio_state_set(!onoff);
  } else if((operation[0] & 0x0f) == 4) {
      if(timeout>0) {
          SM_relay_gpio_state_set(1);
          s_state = 0;
          softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &optionTimer, timeout*32768,  optionTimeroutHandlerCallback,NULL,1);
      }
      else {
          SM_relay_gpio_state_set(0);
      }
  } else if((operation[0] & 0x0f) == 5) {
      if(timeout>0) {
          SM_relay_gpio_state_set(0);
          s_state = 1;
          softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &optionTimer, timeout*32768, optionTimeroutHandlerCallback,NULL,1);
      }
      else {
          SM_relay_gpio_state_set(1);
      }
  }
  if(((operation[0] >> 4)&0x01) != childLockState) {
      childLockState = (operation[0] >> 4)&0x01;
      setThisParam(childLock, &childLockState);
      if(childLockState) {
          outputKeyValue.value[0] |= (0x01<<7);
      }
      else {
          outputKeyValue.value[0] &= ~(0x01<<7);
      }
  }
}

/******************erase device data*********************/

void erase_device_data(void)
{
  resetCalibration();
  NVIC_SystemReset();
}

/****************power on led start***********************/

static void power_on_led_start(void)
{
  uint8_t data[5] = {0};
  data[2] = 0x33;
  data[4] = 0xff;

  if(measure_state_get() != MEASURE_NORMAL) {
      SM_led_start(data, POWER_ON_BLINK);
  }
}

/*******************battery detect***************************/
static MultiTimer iadcTimer;
static uint8_t adcState = 0x00;

static void iadcTimerCallback(MultiTimer* timer, void *userData)
{
  (void)timer;
  (void)userData;

  if(adcState == 0) {
      battery_detect_start(iadcPosInputAvdd);
      adcState = 0x01;
      softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &iadcTimer, 32768*IADC_TIMER_INTERVAL, iadcTimerCallback,NULL,0);
  }
  else if(adcState == 0x01) {
      adcState = 0x00;
      SM_iadc_init();
  }
}

/**
 * @brief: adc init
 * */
static void SM_iadc_init(void)
{
  softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &iadcTimer, 3277, iadcTimerCallback,NULL,0);
}

/**
 * @brief: 获取电压值
 * @return: battery unit:mV
 * */
uint8_t SM_battery_get(void)
{
  uint16_t battery = get_battery_monitor_voltage();
  return battery>1800?(battery/10 - 180):0;
}

/************************temperature get*************************************/

/**
 * @brief: Get the internal temperature of the chip
 * @return: temperature
 * */
int8_t SM_tempDrv_get(void)
{
  float tempCelsius;
  int8_t result;

  tempCelsius = EMU_TemperatureGet();

  if (tempCelsius < INT8_MIN) {
    tempCelsius = INT8_MIN;
  } else if (tempCelsius > INT8_MAX) {
    tempCelsius = INT8_MAX;
  }

  // adding extra 0.5 before truncating to simulate rounding behavior
  result = (((int8_t) (tempCelsius + 0.5 - INT8_MIN)) + INT8_MIN);

  return result;
}

/**********************get hard information***************************/

/**
 * @brief: get hard information
 * @param: point
 * @return: value length
 * */
uint8_t get_hard_information(uint8_t *data)
{
  hardinfo_t hardInfo = {0x00};
  char psn[16] = "DM0080N00001";
  int ret = 0;

  ret = getThisParam(ENpbyKeyM, hardInfo.psn);
  if(ret != 0) {
      memcpy(hardInfo.psn, psn, sizeof(psn));
      setThisParam(ENpbyKeyM, hardInfo.psn);
  }

  ret = getThisParam(ENbyDeviceType, &hardInfo.deviceType);
  if(ret != 0) {
      hardInfo.deviceType = EN_DEVICE_TYPE_IO_SMART_PLUG;
      setThisParam(ENbyDeviceType, &hardInfo.deviceType);
  }

  ret = getThisParam(ENbyModelType, &hardInfo.modelType);
  if(ret != 0) {
      hardInfo.modelType = PLUG_MODEL_TYPE;
      setThisParam(ENbyModelType, &hardInfo.modelType);
  }

  ret = getThisParam(ENbyHardType, &hardInfo.hardType);
  if(ret != 0) {
      hardInfo.hardType = 0x01;
      setThisParam(ENbyHardType, &hardInfo.hardType);
  }

  ret = getThisParam(ENpbyMacID, hardInfo.pmacID);
  if(ret != 0) {
      getMacAddr(hardInfo.pmacID);
      setThisParam(ENpbyMacID, hardInfo.pmacID);
  }

  ret = getThisParam(ENpbyRfVer, hardInfo.pRfVer);
  if(ret != 0
      || hardInfo.pRfVer[0] != MAJOR_VERSION
      || hardInfo.pRfVer[1] != MINOR_VERSION
      || hardInfo.pRfVer[2] != STAGE_VERSION) {
      hardInfo.pRfVer[0] = MAJOR_VERSION;
      hardInfo.pRfVer[1] = MINOR_VERSION;
      hardInfo.pRfVer[2] = STAGE_VERSION;
      setThisParam(ENpbyRfVer, hardInfo.pRfVer);
  }

  ret = getThisParam(ENpbySensorVer, &hardInfo.sensorVer);
  if(ret != 0
      || hardInfo.sensorVer[0] != APP_MAJOR_VERSION
      || hardInfo.sensorVer[1] != APP_MINOR_VERSION
      || hardInfo.sensorVer[2] != APP_STAGE_VERSION) {
      hardInfo.sensorVer[0] = APP_MAJOR_VERSION;
      hardInfo.sensorVer[1] = APP_MINOR_VERSION;
      hardInfo.sensorVer[2] = APP_STAGE_VERSION;
      setThisParam(ENpbySensorVer, &hardInfo.sensorVer);
  }

  memcpy(data, &hardInfo, sizeof(hardInfo));

  return sizeof(hardInfo);
}

/**********************print informatio**************************/
static void printSoftWareInformation(void)
{
  uint8_t macAddr[8] = {0x00};
  getMacAddr(macAddr);
  int16_t txPowerDeciDbm = 0;
  uint32_t ctune = 0;
  char reason[12] = {0};
  uint8_t lfxoTune= 0;
  uint8_t SNNumber[16] = {0x00};

  APP_PRINTF("\r\n*************information***************\r\n");
  uint32_t rst_cause = ds_rmu_init();
  resetToString(rst_cause, reason);
  APP_PRINTF("reset reason   : %s\r\n",reason);
  APP_PRINTF("device mac     : ");
  for(uint8_t i=0;i<7;i++){
      APP_PRINTF("%02x:", macAddr[i]);
  }
  APP_PRINTF("%02x \r\n", macAddr[7]);
  APP_PRINTF("stack version  : v%d.%d.%d \r\n", (STACK_VERSION>>16&0xFF), (STACK_VERSION>>8&0xFF),STACK_VERSION&0xFF);
  APP_PRINTF("app  version   : v%d.%d.%d\r\n", (SENSOR_VERSION>>16&0xFF), (SENSOR_VERSION>>8&0xFF),SENSOR_VERSION&0xFF);
  APP_PRINTF("git  version   : 0x%x\r\n", GIT_VERSION);
  getThisParam(ENpbyKeyM, SNNumber);
  APP_PRINTF("SN number      : %s\r\n", SNNumber);
  APP_PRINTF("device type    : 0x%02X\r\n", EN_DEVICE_TYPE_IO_SMART_PLUG);
  printfDeviceRfFreqInfo();
  getThisParam(RfTxPower, &txPowerDeciDbm);
  APP_PRINTF("device power   : %d \r\n", txPowerDeciDbm);
  getThisParam(RfCtune, &ctune);
  APP_PRINTF("device ctune   : %ld \r\n", ctune);
  getThisParam(lfxoCtune, &lfxoTune);
  APP_PRINTF("device lfxoTune: %d \r\n", lfxoTune);
  APP_PRINTF("build app time : %s %s \r\n", __DATE__, __TIME__);
#ifdef  CONFIG_JENKINS_BUILD_NUMBER
  APP_PRINTF("jenkins build number : %d\r\n", CONFIG_JENKINS_BUILD_NUMBER);
#else
  APP_PRINTF("jenkins build number : 0\r\n");//没定义默认0
#endif
  APP_PRINTF("***************************************\r\n\r\n");
}

/***********************get model api******************************/

static uint8_t device_input_output_state_get(uint8_t *buffer)
{
  buffer[0] = outputKeyValue.value[0];
  buffer[1] = outputKeyValue.value[1];;
  return 2;
}

static uint8_t device_smart_plug_value_get(uint8_t *buffer)
{
  uint8_t index = 0;
  uint16_t power = powerGet();
  buffer[index++] = (power>>8) & 0xFF;
  buffer[index++] = power & 0xFF;
  uint16_t voltage = voltageGet();
  buffer[index++] = voltage & 0xFF;
  uint16_t current = currentGet();
  buffer[index++] = (current>>8) & 0xFF;
  buffer[index++] = current & 0xFF;

  return index;
}

static uint8_t device_smart_plug_energy_get(uint8_t *buffer)
{
  uint8_t index = 0;

  buffer[index++] = (relayticks>>24) & 0xFF;
  buffer[index++] = (relayticks>>16) & 0xFF;
  buffer[index++] = (relayticks>>8) & 0xFF;
  buffer[index++] = relayticks & 0xFF;

  uint32_t energy = summaEnergyGet();
  buffer[index++] = (energy>>24) & 0xFF;
  buffer[index++] = (energy>>16) & 0xFF;
  buffer[index++] = (energy>>8) & 0xFF;
  buffer[index++] = energy & 0xFF;

  return index;
}

uint8_t get_device_state(uint8_t *buffer)
{
  uint8_t data[16] = {0x00};
  uint8_t data_size = 0x00;
  uint8_t index = 0;

  buffer[index] = 0x10;
  index += 1;
  data_size = device_input_output_state_get(data);
  memcpy(&buffer[index], data, data_size);
  memset(data, 0, data_size);
  index += data_size;

  buffer[index] = 0x13;
  index += 1;
  data_size = device_smart_plug_value_get(data);
  memcpy(&buffer[index], data, data_size);
  memset(data, 0, data_size);
  index += data_size;

  buffer[index] = 0x14;
  index += 1;
  data_size = device_smart_plug_energy_get(data);
  memcpy(&buffer[index], data, data_size);
  memset(data, 0, data_size);
  index += data_size;

  return index;
}

static MultiTimer findMeTimer;

static void findMeTimerCallback(MultiTimer* timer, void *userData)
{
  (void)timer;
  (void)userData;
  uint8_t data[5] = {0};
  SM_led_start(data, NONE_BLINK);
}

void SM_device_QRF_state_Handle(QRFH1_t qrfH1, QRFH2_t qrfH2)
{
  (void)qrfH1;
  uint8_t data[5] = {0};
  if(qrfH2.isFM == 1) {
      data[2] = 240;
      data[3] = 1;
      data[4] = 15;
      SM_led_start(data, FIND_ME_BLINK);
      softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &findMeTimer,0);
      softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &findMeTimer, 32768*30, findMeTimerCallback,NULL,0);
  }
  else {
      if(findMeTimer.status != EN_MULTITIMER_STATUS_IDLE) {
          softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &findMeTimer,0);
          SM_led_start(data, NONE_BLINK);
      }
  }
}
void calibration_finist_callback(void)
{
  uint8_t data[5] = {0};

  SM_led_start(data, NONE_BLINK);
}

static void reportVoltPower(void)
{
  keyValue_t VoltCPower = {0x00};
  uint8_t buffer[8] = {0x00};

  VoltCPower.id = 0x13;
  VoltCPower.valueSize = 5;
  device_smart_plug_value_get(buffer);
  memcpy(VoltCPower.value, buffer, 5);
  set_key_value(&VoltCPower);
}

static void current_overload_callback(uint16_t current)
{
  (void)current;
  SM_relay_gpio_state_set(0);
  if(((outputKeyValue.value[1] >> 3) & 0x01) == 0x00) {
      outputKeyValue.value[1] |= (0x01<<3);
      reportVoltPower();
  }
  set_key_value(&outputKeyValue);
}

static void current_normal_callback(uint16_t current)
{
  (void)current;
  if(((outputKeyValue.value[1] >> 3) & 0x01) == 0x01) {
      outputKeyValue.value[1] &= ~(0x01<<3);
      set_key_value(&outputKeyValue);
      reportVoltPower();
  }
}

static void power_overload_callback(uint16_t power)
{
  (void)power;
  SM_relay_gpio_state_set(0);
  if(((outputKeyValue.value[1] >> 5) & 0x01) == 0x00) {
      outputKeyValue.value[1] |= (0x01<<5);
      reportVoltPower();
  }
  set_key_value(&outputKeyValue);
}

static void power_normal_callback(uint16_t power)
{
  (void)power;
  if(((outputKeyValue.value[1] >> 5) & 0x01) == 0x01) {
      outputKeyValue.value[1] &= ~(0x01<<5);
      set_key_value(&outputKeyValue);
      reportVoltPower();
  }
}

static void voltage_overload_callback(uint16_t voltage)
{
  (void)voltage;
  if(((outputKeyValue.value[1] >> 2) & 0x01) == 0x00 ||  SM_relay_state_get() == 0x01) {
      SM_relay_gpio_state_set(0);
      outputKeyValue.value[1] &= ~(0x01<<4);
      outputKeyValue.value[1] |= (0x01<<2);
      set_key_value(&outputKeyValue);
      reportVoltPower();
  }
}

static void voltage_under_callback(uint16_t voltage)
{
  (void)voltage;
  if(((outputKeyValue.value[1] >> 4) & 0x01) == 0x00 || SM_relay_state_get() == 0x01) {
      SM_relay_gpio_state_set(0);
      outputKeyValue.value[1] &= ~(0x01<<2);
      outputKeyValue.value[1] |= (0x01<<4);
      set_key_value(&outputKeyValue);
      reportVoltPower();
  }
}

static void voltage_normal_callback(uint16_t voltage)
{
  (void)voltage;
  if((((outputKeyValue.value[1] >> 4) & 0x01) == 0x01)
      || (((outputKeyValue.value[1] >> 2) & 0x01) == 0x01)) {
      outputKeyValue.value[1] &= ~(0x01<<4);
      outputKeyValue.value[1] &= ~(0x01<<2);
      set_key_value(&outputKeyValue);
      reportVoltPower();
  }
}

static void energyStateCallbackInit(void)
{
  energyStateCallbackRegister(currentOverload, current_overload_callback);
  energyStateCallbackRegister(currentNormal, current_normal_callback);
  energyStateCallbackRegister(powerOverload, power_overload_callback);
  energyStateCallbackRegister(powerNormal, power_normal_callback);
  energyStateCallbackRegister(voltageOverload, voltage_overload_callback);
  energyStateCallbackRegister(voltageUnderload, voltage_under_callback);
  energyStateCallbackRegister(voltageNomal, voltage_normal_callback);
}

void led_blink_finist_callback(blinkType_t type)
{
  (void)type;
  set_led_state();
}

/**********************set gpio mode default*************************/

void staticPowerGpioInit(void)
{
}

#endif
